﻿using System.Collections.Generic;
using UnityEngine;

namespace AI.Graph {


    public class AIControllerSerializer {

        private AIController m_originalController;
        private AIController m_copiedController;
        private readonly Dictionary<Node, Node> m_nodes = new Dictionary<Node, Node> ();
        private readonly Dictionary<ConnectionPort, ConnectionPort> m_ports = new Dictionary<ConnectionPort, ConnectionPort> ();


        private AIControllerSerializer () { }


        public AIController copiedController {
            get {
                if (m_copiedController != null) {
                    return m_copiedController;
                }

                Debug.LogError ("The given original controller was not copied!");
                return null;
            }
        }


        /// <summary>
        /// Copy the given Node.
        /// </summary>
        /// <param name="original">The original node.</param>
        /// <returns>Returns a copy of the given Node.</returns>
        public T GetCopyOf<T> (T original) where T : Node {
            if (m_nodes.ContainsKey (original)) {
                return (T) m_nodes[original];
            }

            Debug.LogError ("The given original node was not copied!");
            return null;
        }


        /// <summary>
        /// Copy the given PortReference.
        /// </summary>
        /// <param name="original">The original PortReference.</param>
        /// <returns>Returns a copy of the given PortReference.</returns>
        public ConnectionPort GetCopyOf (ConnectionPort original) {
            if (m_ports.ContainsKey (original)) {
                return m_ports[original];
            }

            Debug.LogError ("The given original port was not copied!");
            return null;
        }


        /// <summary>
        /// Creates a deep copy of the given controller.
        /// </summary>
        /// <param name="originalController">The controller to copy.</param>
        /// <returns>Returns a deep copy of the given controller.</returns>
        public static AIController Copy (AIController originalController) {
            // Create a copy of the existing controller.
            AIControllerSerializer serializer = new AIControllerSerializer {
                m_originalController = originalController,
                m_copiedController = Object.Instantiate (originalController)
            };

            // create a copy of all nodes and port references.
            foreach (Node originalNode in serializer.m_originalController.nodes) {
                Node copyNode = Object.Instantiate (originalNode);
                copyNode.name = originalNode.name;
                serializer.m_nodes.Add (originalNode, copyNode);

                foreach (ConnectionPort originalPort in originalNode.ports) {
                    ConnectionPort copyPort = Object.Instantiate (originalPort);
                    copyPort.name = originalPort.name;
                    serializer.m_ports.Add (originalPort, copyPort);
                }
            }

            // deep copy port references. 
            foreach (ConnectionPort originalPort in serializer.m_ports.Keys) {
                ConnectionPort copyPort = serializer.m_ports[originalPort];
                copyPort.Copy (serializer, originalPort);
            }

            // deep copy node references.
            foreach (Node originalNode in serializer.m_nodes.Keys) {
                Node copyNode = serializer.m_nodes[originalNode];
                copyNode.Copy (serializer, originalNode);
            }

            // deep copy controller references.
            serializer.m_copiedController.Copy (serializer, serializer.m_originalController);

            return serializer.m_copiedController;
        }

    }


}